'''

    2024年6月19日09:38:13
    批改作业的小程序2.0
    不再依赖于chatgpt，使用本地的千问
    尝试让AI阅读word文档：QWEN2+QWENVL
    思路：让QWENVL把图片给理解了，描述下图片，然后把作业内容和图片描述一起传给QWNE2让他给评语
    遍历指定目录下的所有.docx文件和.doc文件，然后直接追加评语和等级
    修改参数：
        一个拥有资深授课经验的老教师,教授课程为区块链原理与应用  修改教授课程
        FILE_DIR 要批改的作业文件夹，批改目录下所有word
        LOG_FILE 日志文件
        SCORE_FILE 简要记录成绩的文件
        PROMPT 提示词
        READ_IMG 是否读图的标志
'''
import json
import os
import re
import sys
from os.path import basename
from time import sleep

import docx
import requests
import win32com.client as wc
import random
import datetime
import shutil
import traceback

from PIL import ImageGrab
from win32com.client import constants

qwvl_url = 'http://192.168.195.156:19999/getDes'
qw_url = 'http://192.168.195.156:18888/qwen'
## 获得评语AI版
def getPingyuAI(num):
    pingyu_result = []
    return pingyu_result
def printAndLogs(info):
    print(info)
    # logs.append(info)
    ## 3.写入日志
    with open(LOG_FILE, 'a+') as f:
        # # 写入文本
        # log_info = "本次任务发起时间为:" + datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') + "\n"
        f.writelines(info + '\n')
        # 每个元素后面加上换行符
        # sents = [log + '\n' for log in logs]
        # # 写入
        # f.writelines(sents)

def saveScore(info):
    ## 4.记录成绩
    with open(SCORE_FILE, 'a+') as f:
        # # 写入文本
        # log_info = "本次任务发起时间为:" + datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') + "\n"
        f.writelines(info + "\n")
        # # 每个元素后面加上换行符
        # sents = [score + '\n' for score in score_list]
        # # 写入
        # f.writelines(sents)



    ## 1 遍历指定目录下的所有.docx文件和.doc文件
FILE_DIR = "D:\批改作业\例子\\01"
LOG_FILE = FILE_DIR + "\\logs.txt"
SCORE_FILE = FILE_DIR + "\\score.txt"
PROMPT = ("你是一位经验丰富的授课老师，请根据作业内容，给出一个严格要求下的评语，要求评语长度在200个字左右并指出优点和不足。同时给出一个等级，在ABCD中选择，等级越高，评语相对来讲越优秀。在最后留下批改时间，也就是现在的系统时间，例如2024年7月2日"
          "。作业内容：")
READ_IMG = True




## 待处理的文件列表

FILE_PRO_LIST = []
logs = []

## 1.0 备份
source_path = os.path.abspath(FILE_DIR)
target_path = os.path.abspath(FILE_DIR+"_自动备份")
if not os.path.exists(target_path):
    if not os.path.exists(target_path):
        # 如果目标路径不存在原文件夹的话就创建
        os.makedirs(target_path)
    if os.path.exists(source_path):
        # 如果目标路径存在原文件夹的话就先删除
        shutil.rmtree(target_path)
    shutil.copytree(source_path, target_path)
printAndLogs('【@完成备份@】')

## 1.1 开始遍历指定目录
printAndLogs("1.开始遍历目录，探测需要修改的文档。。。")
for root, dirs, files in os.walk(FILE_DIR):
    for file in files:
        ## 1.2 开始判断文件是否是word
        filename = os.path.join(root,file)
        ## 1.2.1 判断是否已批改
        if filename.find("-已批改") > 0:
            continue
        if (filename.endswith(".doc")):
            ## 1.3 如果是doc文件，另存为.docx文件，然后把doc删掉
            # print(filename)
            try:
                word = wc.Dispatch('word.Application')
                doc = word.Documents.Open(filename)
                doc.SaveAs(filename + "x", 12)
                file = file + "x"
                doc.Close()
                os.remove(filename)
            except:
                continue
            sleep(1)
            printAndLogs("  doc文件已转为docx【" + filename + "x】")
            filename += "x"

        if(filename.endswith(".docx")):
            ## 1.3 加入待处理列表
            # print(filename)
            FILE_PRO_LIST.append(filename)
# print(FILE_PRO_LIST)
printAndLogs("  探测完成！需编写评语的作业有【"+str(len(FILE_PRO_LIST))+"】份")
## 2 操作word文件进行追加评语
from docx import Document
from docx.shared import RGBColor,Pt
from openpyxl import load_workbook

printAndLogs("2.开始尝试批改作业。。。")

index = 0
lese = []
score_list = []
all_number = len(FILE_PRO_LIST)
first_flag = 1

word = wc.Dispatch('word.Application')
word.Visible = False

# 创建一个目录来保存图片
images_dir = 'extracted_images'
if not os.path.exists(images_dir):
    os.makedirs(images_dir)


for filepath in FILE_PRO_LIST:
    # sleep(5) # 避免开文件太快报错
    ## 有的同学不讲武德，doc文件硬改docx ，python-docx不能改
    try:
        print(filepath)
        doc = Document(filepath)
    except Exception as e:
        print(e)
        try:
            doc = Document(filepath)
            doc.SaveAs(filepath, 12)
        except Exception as ee:
            print(ee)
            continue
        printAndLogs("  有个地雷！doc文件已转为docx【C"+filepath+"】")
        printAndLogs("  进度"+str(index+1)+"/"+str(all_number)+"给【"+filepath+"】添加评语失败！")
        print( traceback.format_exc())
        index += 1
        lese.append(filepath)
        continue

    # 获取文档末尾段落
    try:
        # 提取docx文本内容
        a = list()
        pattern = re.compile('rId\d+')
        isFirst = True
        for graph in doc.paragraphs:
            for run in graph.runs:
                if run.text != '':
                    a.append(run.text)
                else:
                    # aaa = run.element.xml
                    # print(run.element.xml)
                    if not READ_IMG:
                        continue
                    try:
                        contentID = pattern.search(run.element.xml).group(0)
                    except AttributeError as e:
                        print(e)
                        continue
                    try:
                        contentType = doc.part.related_parts[contentID].content_type
                    except KeyError as e:
                        print(e)
                        continue
                    if not contentType.startswith('image'):
                        continue
                    # 如果是学校Logo，跳过
                    if isFirst:
                        isFirst = False
                        continue
                    imgName = basename(doc.part.related_parts[contentID].partname)
                    image_path = images_dir + "\\" + imgName
                    with open(image_path, "wb") as f:
                        f.write(doc.part.related_parts[contentID].blob)
                        print(f'  图片已保存到: {image_path}')
                    # 解读图片
                    current_dir = os.getcwd()
                    # 将当前目录与图片目录结合
                    absolute_images = os.path.join(current_dir + "\\" + image_path)
                    with open(absolute_images, 'rb') as img:
                        # # 设置请求头
                        # headers = {'Content-Type': 'multipart/form-data'}
                        # 发送POST请求，'file'是服务器端接收文件的字段名
                        try:
                            response = requests.post(qwvl_url, files={'file': img})
                            res = json.loads(response.text).get('res')
                            print(res)
                        except Exception as e:
                            print(f"发生了一个错误：{e}：{response}")
                    a.append("此处是一张图片，图片内容为：" + res)
        # 获取评语
        nr = ' '.join(a)
        print(len(nr))
        if len(nr) > 7000:
            nr = nr[:7000]
        response = requests.get(qw_url, params={"query": PROMPT + nr })
        res = json.loads(response.text).get('answer')

        # 在段落末尾添加红色文字
        pingyu_nr = res
        p = doc.paragraphs[-1]
        p.add_run("    ")
        run = p.add_run(pingyu_nr)
        font = run.font
        font.color.rgb = RGBColor(255, 0, 0)  # 设置文字颜色为红色
        doc.save(filepath[:-5]+"-已批改"+filepath[-5:])
        os.remove(filepath)
        printAndLogs("  进度"+str(index+1)+"/"+str(all_number)+"已给【"+filepath+"】添加评语")
        # printAndLogs("     评语为：" + pingyu_nr)
        # score_list.append(filepath+"  ：  "+pingyu_nr)
        saveScore(filepath + "  :  " + pingyu_nr)
        index += 1
    except:
        printAndLogs("  进度"+str(index+1)+"/"+str(all_number)+"给【"+filepath+"】添加评语失败！")
        print( traceback.format_exc())
        index += 1
        lese.append(filepath)
        continue

printAndLogs("批量添加评语完成，失败【"+str(len(lese))+"】份！")
for item in lese:
    printAndLogs("  "+item)


